<?php
/**
 *  Generic Default Model: a class for item-based model management:
 *      - the data source is the DB
 *      - the record properties are taken from Module config
 *  Similar to Active Record pattern, in which the record is implemented in Item,
 *      and the data access in Action.
 *
 *  @todo select item externally ? or leave it up to subclass only
 *
 */
namespace Yz\modules\Generic;

class Model_Default
    extends Model_Abstract
{


    /************************************
     *          Public methods          *
     ************************************/


    /**
     *
     *  @param int $id
     *  @return Yz_Item_Interface
     *  @throws NotFound
     */
    public function fetchItemById($id)
    {
        debug();
        $action = $this
            ->selectAction('SelectById')
            ->setId($id)
        ;
        return $this->_fetch( $action );
    }

    /**
     *
     *  @param Yz_Item_Interface $item
     *  @return Yz_Item_Interface
     */
    public function fetchPreviousItem(\Yz_Item_Interface $item)
    {
        debug();
        return $this->_fetchNeighborItem( $item, false ) ;
    }

    /**
     *
     *  @param Yz_Item_Interface $item
     *  @return Yz_Item_Interface
     */
    public function fetchNextItem(\Yz_Item_Interface $item)
    {
        debug();
        return $this->_fetchNeighborItem( $item, true ) ;
    }


    /**
     *  updateItemById
     *
     *  @return chainable
     */
    public function updateItemById(\Yz_Item_Interface $item)
    {
        debug();
        $action = $this
            ->selectAction('UpdateById')
            ->setId($item->id)
        ;
        return $this->_update($item, $action);
    }

    /**
     *
     *  @return int insert-id/sequence#
     */
    public function createItem()
    {
        debug();
        $action = $this->selectAction('Insert');
        return $action
            ->perform()
            ->getInsertId()
        ;
    }

    /**
     *
     *  @return int insert-id/sequence#
     */
    public function addItem(\Yz_Item_Interface $item)
    {
        debug();
        $newId = $this
            ->selectAction('Insert')
            ->assignFields($item->describe())
            ->assignValues($item)
            ->perform()
            ->getInsertId()
        ;
        $item->id = $newId;
        return $this;
    }

    /**
     *
     *  @return chainable
     */
    public function deleteItemById(\Yz_Item_Interface $item)
    {
        debug();
        $this
            ->selectAction('DeleteById')
            ->setId($item->id)
            ->perform()  // returns action (ignored) or throws exception
        ;

        return $this;
    }

    /************************************
     *       Protected methods          *
     ************************************/


    protected function _fetchNeighborItem(/* Yz_Item_Interface */ $item, $isNext)
    {
        $id = $item->id;
        static $action;
        if (null === $action) {
            $action = $this
                ->selectAction('SelectNeighbor')
                ->assignFields($item->describe())
            ;
        }
        if ($isNext) {
            $action->selectNextItem();
        } else {
            $action->selectPreviousItem();
        }
        $c = $action
            ->setId($id)
            ->execute()
            ->count()
        ;
        if (0 === $c) {
            return null;
        }
        $item0 = clone($item);
        return $item0->assignValues($action->fetch());
    }

}
